function states_ = gXmodality_statelist(varargin)

% arguments to make statelist polymorphic
if nargin < 7
    error('need 7 arguments')
else
    respond = varargin{1};
    up = varargin{3};
    down = varargin{4};
    left = varargin{5};
    right = varargin{6};
    post = varargin{7};
    targets = varargin{8};
end

% long wait-for-response time
show = 5000;

% confirm-or-modify-response time
hang = 100;

% acquire central fixation
acquire = { ...
    'dXkbHID',  {'any', 'error'}; ...
    'dXPMDHID', {[9;11], 'error'}; ...
    'dXasl',    {[1,true,inf], 'hold', true}};

% hold central or rebound to acquire
hold = { ...
    'dXkbHID',  {'any', 'error'}; ...
    'dXPMDHID', {'any', 'error'}; ...
    'dXasl',    {[1,false,inf], 'acquire', true}};

% settle on tighter fixation or rebound to acquire
settle = { ...
    'dXkbHID',  {'any', 'error'}; ...
    'dXPMDHID', {'any', 'error'}; ...
    'dXasl',    {[2,false,inf], 'acquire', true}};

% maintain central fixation with friendly restart
fixate = { ...
    'dXkbHID',  {'any', 'error'}; ...
    'dXPMDHID', {'any', 'error'}; ...
    'dXasl',    {[2,false,inf], 'error', true}};

% correct response depends on random stimulus
%   for dXlr, 0=left, 1=right
%   for dXdu, 0=down, 1=up
lcon = {'jump', {'dXlr', 1, 'value'}, [0 1], {'correct'; 'incorrect'}};
rcon = {'jump', {'dXlr', 1, 'value'}, [0 1], {'incorrect'; 'correct'}};
dcon = {'jump', {'dXdu', 1, 'value'}, [0 1], {'correct'; 'incorrect'}};
ucon = {'jump', {'dXdu', 1, 'value'}, [0 1], {'incorrect'; 'correct'}};

% state function and argument shorthand
GS = @rGraphicsShow;
fp = {'dXtarget', 1};
dt = {'dXdots', 1};
ndt = {{},dt{:}};

CT = @centerTargetOnFixation;
ctf = {2, 300, 'diameter2', 2, 'visible', true};

SE = @rSet;
fpd2up = {'dXtarget', 2, 'diameter2', 6};

SP = @rPlay;
bp = 'dXbeep';
sd = 'dXsound';

VU = @rVarUpdate;
ptrs = {'dXtc', 'dXquest', 'dXlr', 'dXdu'};

GC = @showDotsCheckFP;

%   name        fun args        jump    wait    repsDrawQuery   cond
arg_dXstate = {{ ...
    'clear',    {}, {},         'next', 0,      0,  5,  0,      {}; ...
    'indicate', GS, fp,         'next', 0,      0,  3,  0,      {}; ...
    'acquire',  {}, {},         'error',3e4,    0,  0   acquire,{}; ...
    'hold',     {}, {},         'next', 350,    0,  0,  hold,   {}; ...
    'recenter', CT, ctf,        'next', 0,      0,  3,  1,      {}; ...
    'settle',   {}, {},         'next', 150,    0,  0,  settle, {}; ...
    ...
    'tone1',	SP, {bp,1},     'next', 100,	0,  0,  1,      {}; ...
    'nextStim',	VU, ptrs,       'next', 600,    0,  0,  1,      {}; ...
    'onStim',	GC, {dt,fp},	'next', 100,    0,  0,  1,      {}; ...
    'onTarg',	GS, targets,    'next', 100,    0,  0,  1,      {}; ...
    'tone2',	SP, {bp,2},     'next', 100,	0,  0,  fixate, {}; ...
    'resize',   SE, fpd2up,     'next', 0,      0,  0,  1,      {}; ...
    'showStim', {}, {},         'error',show,   0,  1,  respond,{}; ...
    ...
    'choose',   GS, ndt,        'error',post,   0,  3,  choose, {}; ...
    'left',     GS, ndt,        'error',hang,	0,  3,  left,   lcon; ...
    'right',    GS, ndt,        'error',hang,	0,  3,  right,  rcon; ...
    'up',       GS, ndt,        'error',hang,	0,  3,  up,     ucon; ...
    'down',     GS, ndt,        'error',hang,	0,  3,  down,	dcon; ...
    'both',     {}, {},         'error',0,      0,  0,  0,      {}; ...
    ...
    'correct',  SP, {sd,1},     'end',  500,	0,  0,  0,      {}; ...
    'incorrect',SP, {sd,2},     'end',  500,	0,  0,  0,      {}; ...
    'error',    SP, {sd,3},     'next', 500,	0,  5,  0,      {}; ...
    'end',      {}, {},         'x',    0,      0,  5,  0,      {}; ...
    }};
sz = size(arg_dXstate{1}, 1);

tony = {'current', true, true, false};
states_ = {'dXstate', sz, tony, arg_dXstate};